/*
 *  Copyright (C) 2010 Glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.application;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Level;
import org.balisunrise.common.PropertiesReader;

/**
 * Classe que carrega arquivos JAR para o classpath do sistema.
 *
 * @author Glauco
 */
public class JarLoader
{

    private static final Class[] parameters = new Class[]{URL.class};

    List<Class> classes;

    List<JarInfo> jarInfos;

    public JarLoader ()
    {
        classes = new ArrayList<Class>();
        jarInfos = new ArrayList<JarInfo>();
    }

    /**
     * Addiciona um arquivo JAR ao classPath.
     * @param path endereço do arquivo JAR
     * @return um JarInfo com informações do arquivo JAR carregado.
     * @throws IOException
     * @see JarInfo
     */
    public JarInfo addFile (String path) throws IOException
    {
        File file = new File(path);
        URL url = file.toURI().toURL();

        URLClassLoader sysloader = (URLClassLoader)
                ClassLoader.getSystemClassLoader();
        Class sysclass = URLClassLoader.class;

        try {
            Method method = sysclass.getDeclaredMethod("addURL",parameters);
            method.setAccessible(true);
            method.invoke(sysloader,new Object[]{ url });
        } catch (Throwable t) {
            String msg = "Error, could not add URL to system classloader";
            Application.get().getLogger().log(Level.SEVERE, msg, t);
            throw new IOException(msg);
        }

        JarInfo jarInfo = new JarInfo();

        List<String> entries = new ArrayList<String>();

        Manifest mf = null;

        try{
            JarFile jar = new JarFile(path);
            
            jarInfo.mf = jar.getManifest();

            Enumeration<JarEntry> enumeration = jar.entries();
            while(enumeration.hasMoreElements()){
                JarEntry entry = enumeration.nextElement();
                if(!entry.isDirectory())
                    entries.add(entry.getName());
            }
        }catch(Exception e){
            System.out.println(e.getMessage());
        }

        // TODO: remover estes print sout
        System.out.println("Listando Classes:");
        for (String string : entries) {
            if (string.contains(".class") && !string.contains("$")){
                String className = string.replace('/','.')
                        .replace(".class", "");
                try{
                    Class clazz = Class.forName(className);
                    jarInfo.classes.add(clazz);
                    classes.add(clazz);
                    System.out.println("CLASS: " + clazz.getName());
                }catch(ClassNotFoundException cnfex){
                    System.out.println("Problema: " + cnfex.getMessage());
                }
            }
        }
        System.out.println("Fim da listagem, nº de classes carregadas: "
                + classes.size() + "!");

        jarInfos.add(jarInfo);

        jarInfo.processClasses();

        return jarInfo;
    }

    /**
     * carrega os jars do sistema.
     * @return Um Array de JarInfo
     * @throws IOException
     * @see JarInfo
     */
    public JarInfo[] loadSystemJars() throws IOException{
        
        String allJars = Application.get().getPropertiesReader()
                .readProperty(PropertiesReader.jars);

        if (allJars == null)
            return new JarInfo[0];
        
        String jars[];
        if (allJars.contains(";"))
            jars = allJars.split(";");
        else
            jars = new String[]{allJars};

        if(jars.length == 0)
            return new JarInfo[0];

        List<JarInfo> jis = new ArrayList<JarInfo>();

        for (String jarPath : jars) {
            JarInfo j = addFile(jarPath);
            jis.add(j);
        }

        return jis.toArray(new JarInfo[jis.size()]);
    }
}